﻿using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Romantics.Domain;
using Romantics.Domain.Objects;
using Romantics.Models;
using Romantics.Providers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;

namespace Romantics.Controllers
{
    [Authorize]
    public class AdminController : Controller
    {
        private readonly IAuthProvider _authProvider;
        private readonly IDomainRepository _domainRepository;

        public AdminController(IAuthProvider authProvider, IDomainRepository domainRepository = null)
        {
            _authProvider = authProvider;
            _domainRepository = domainRepository;
        }

        [AllowAnonymous]
        public ActionResult Login(string returnUrl)
        {
            if (_authProvider.IsLoggedIn)
                return RedirectToUrl(returnUrl);

            ViewBag.ReturnUrl = returnUrl;

            return View();
        }

        [HttpPost, AllowAnonymous, ValidateAntiForgeryToken]
        public ActionResult Login(LoginModel model, string returnUrl)
        {
            if (ModelState.IsValid)
            {
                if (FormsAuthentication.Authenticate(model.UserName, model.Password))
                {
                    FormsAuthentication.SetAuthCookie(model.UserName, false);

                    if (!String.IsNullOrEmpty(returnUrl) && Url.IsLocalUrl(returnUrl))
                        return Redirect(returnUrl);

                    return RedirectToAction("Manage");
                }

                ModelState.AddModelError("", "Неверное имя пользователя или пароль. Проверьте правильность введенных данных.");
            }
            return View();
        }

        public ActionResult Logout()
        {
            FormsAuthentication.SignOut();

            return RedirectToAction("Login", "Admin");
        }

        public ActionResult Manage()
        {
            return View();
        }

        private ActionResult RedirectToUrl(string returnUrl)
        {
            if (Url.IsLocalUrl(returnUrl))
            {
                return Redirect(returnUrl);
            }
            else
            {
                return RedirectToAction("Manage");
            }
        }

        #region Generic actions

        private ContentResult Add<U>(U entity) where U:Entity
        {
            string json;

            ModelState.Clear();

            if (TryValidateModel(entity))
            {
                var id = _domainRepository.Add<U>(entity);

                json = JsonConvert.SerializeObject(new
                {
                    id = id,
                    success = true,
                    message = "Новая запись добавлена."
                });
            }
            else
            {
                json = JsonConvert.SerializeObject(new
                {
                    id = 0,
                    success = false,
                    message = "Невозможно сохранить новую запись: " + ModelState.Values.First(x => x.Errors.Count >= 1).Errors[0].ErrorMessage
                });
            }

            return Content(json, "application/json");
        }

        private ContentResult Edit<U>(U entity) where U : Entity
        {
            string json;

            ModelState.Clear();

            if (TryValidateModel(entity))
            {
                _domainRepository.Edit<U>(entity);
                json = JsonConvert.SerializeObject(new
                {
                    id = entity.ID,
                    success = true,
                    message = "Изменения внесены."
                });
            }
            else
            {
                json = JsonConvert.SerializeObject(new
                {
                    id = 0,
                    success = false,
                    message = "Невозможно внести изменения: " + ModelState.Values.First(x => x.Errors.Count >= 1).Errors[0].ErrorMessage
                });
            }

            return Content(json, "application/json");
        }

        private ContentResult Delete<U>(int id) where U : Entity
        {
            _domainRepository.Delete<U>(id);

            var json = JsonConvert.SerializeObject(new
            {
                id = 0,
                success = true,
                message = "Запись удачно удалена."
            });

            return Content(json, "application/json");
        }

        #endregion

        #region Сountry

        public ActionResult Countries(JqInViewModel jqParams)
        {
            var сountries = _domainRepository.Countries(
                  jqParams.page - 1
                , jqParams.rows
                , jqParams.sidx
                , jqParams.sord == "asc"
                ).ToList();

            var totalCountries = _domainRepository.Total<Country>();
            JsonSerializerSettings serializerSettings = new JsonSerializerSettings();
            return Content(JsonConvert.SerializeObject(new
                {
                    page = jqParams.page,
                    records = totalCountries,
                    rows = сountries,
                    total = Math.Ceiling(Convert.ToDouble(totalCountries) / jqParams.rows)
                }
                , serializerSettings)
                , "application/json");
        }

        [HttpPost, ValidateInput(false)]
        public ContentResult AddCountry(Country country)
        {
            return Add<Country>(country);
        }

        [HttpPost, ValidateInput(false)]
        public ContentResult EditCountry(Country country)
        {
            return Edit<Country>(country);
        }

        [HttpPost]
        public ContentResult DeleteCountry(int id)
        {
            return Delete<Country>(id);
        }

        public ContentResult GetCountriesHtml()
        {
            var countries = _domainRepository.Countries(0, Int32.MaxValue, "name", true);

            var sb = new StringBuilder();
            sb.AppendLine(@"<select>");

            foreach (var country in countries)
            {
                sb.AppendLine(String.Format(@"<option value=""{0}"">{1}</option>",
                    country.ID, country.Name));
            }

            sb.AppendLine("<select>");
            return Content(sb.ToString(), "text/html");
        }

        #endregion

        #region Region

        public ActionResult Regions(JqInViewModel jqParams)
        {
            var сountries = _domainRepository.Regions(
                  jqParams.page - 1
                , jqParams.rows
                , jqParams.sidx
                , jqParams.sord == "asc"
                , jqParams.name
                , jqParams.country
                ).ToList();

            var totalRegions = _domainRepository.Total<Region>();
            JsonSerializerSettings serializerSettings = new JsonSerializerSettings();
            var converter = new IsoDateTimeConverter();
            converter.DateTimeFormat = "yyyy-MM-dd";
            serializerSettings.Converters.Add(converter);
            return Content(JsonConvert.SerializeObject(new
                {
                    page = jqParams.page,
                    records = totalRegions,
                    rows = сountries,
                    total = Math.Ceiling(Convert.ToDouble(totalRegions) / jqParams.rows)
                }
                , serializerSettings)
                , "application/json");
        }

        [HttpPost, ValidateInput(false)]
        public ContentResult AddRegion(Region region)
        {
            return Add<Region>(region);
        }

        [HttpPost, ValidateInput(false)]
        public ContentResult EditRegion(Region region)
        {
            return Edit<Region>(region);
        }

        [HttpPost]
        public ContentResult DeleteRegion(int id)
        {
            return Delete<Region>(id);
        }

        public ContentResult GetRegionsHtml()
        {
            var regions = _domainRepository.Regions(0, Int32.MaxValue, "Country", true);

            var sb = new StringBuilder();
            sb.AppendLine(@"<select>");

            foreach (var region in regions)
            {
                sb.AppendLine(String.Format(@"<option value=""{0}"">{1}. {2}</option>",
                    region.ID, region.Country.Name, region.Name));
            }

            sb.AppendLine("<select>");
            return Content(sb.ToString(), "text/html");
        }

        #endregion

        #region Hike

        public ActionResult Hikes(JqInViewModel jqParams)
        {
            var hikes = _domainRepository.Hikes(
                  jqParams.page - 1
                , jqParams.rows
                , jqParams.sidx
                , jqParams.sord == "asc"
                , jqParams.name
                , jqParams.category
                , jqParams.region
                ).ToList();

            var totalHikes = _domainRepository.Total<Hike>();
            JsonSerializerSettings serializerSettings = new JsonSerializerSettings();
            var converter = new IsoDateTimeConverter();
            converter.DateTimeFormat = "yyyy-MM-dd";
            serializerSettings.Converters.Add(converter);
            return Content(JsonConvert.SerializeObject(new
                {
                    page = jqParams.page,
                    records = totalHikes,
                    rows = hikes,
                    total = Math.Ceiling(Convert.ToDouble(totalHikes) / jqParams.rows)
                }
                , serializerSettings)
                , "application/json");
        }

        [HttpPost, ValidateInput(false)]
        public ContentResult AddHike(Hike hike)
        {
            return Add<Hike>(hike);
        }

        [HttpPost, ValidateInput(false)]
        public ContentResult EditHike(Hike hike)
        {
            return Edit<Hike>(hike);
        }

        [HttpPost]
        public ContentResult DeleteHike(int id)
        {
            return Delete<Hike>(id);
        }

        public ContentResult GetHikesHtml()
        {
            var hikes = _domainRepository.Hikes(0, Int32.MaxValue, "StartDate", false)
                .Where(h => h.Published && h.StartDate < DateTime.Now && DateTime.Now.Year - h.StartDate.Year <= 2);

            var sb = new StringBuilder();
            sb.AppendLine(@"<select>");

            foreach (var hike in hikes)
            {
                sb.AppendLine(String.Format(@"<option value=""{0}"">{1} [{2}]</option>",
                    hike.ID, hike.Name, hike.StartDate.ToString("d")));
            }

            sb.AppendLine("<select>");
            return Content(sb.ToString(), "text/html");
        }
        #endregion

        #region Category

        public ActionResult Categories(JqInViewModel jqParams)
        {
            var categories = _domainRepository.Categories().OrderBy(s => s.Name);

            var totalCategories = _domainRepository.Total<Category>();
            JsonSerializerSettings serializerSettings = new JsonSerializerSettings();
            return Content(JsonConvert.SerializeObject(new
            {
                page = jqParams.page,
                records = totalCategories,
                rows = categories,
                total = Math.Ceiling(Convert.ToDouble(totalCategories) / jqParams.rows)
            }
                , serializerSettings)
                , "application/json");
        }

        [HttpPost, ValidateInput(false)]
        public ContentResult AddCategory(Category category)
        {
            return Add<Category>(category);
        }

        [HttpPost, ValidateInput(false)]
        public ContentResult EditCategory(Category category)
        {
            return Edit<Category>(category);
        }

        [HttpPost]
        public ContentResult DeleteCategory(int id)
        {
            return Delete<Category>(id);
        }

        public ContentResult GetCategoriesHtml()
        {
            var categories = _domainRepository.Categories().OrderBy(s => s.Name);

            var sb = new StringBuilder();
            sb.AppendLine(@"<select>");

            foreach (var category in categories)
            {
                sb.AppendLine(string.Format(@"<option value=""{0}"">{1}</option>",
                    category.ID, category.Name));
            }

            sb.AppendLine("<select>");
            return Content(sb.ToString(), "text/html");
        }

        #endregion

        #region Options

        public ActionResult Options(JqInViewModel jqParams)
        {
            var options = _domainRepository.OptionList();

            JsonSerializerSettings serializerSettings = new JsonSerializerSettings();
            return Content(JsonConvert.SerializeObject(new
            {
                page = jqParams.page,
                records = 1,
                rows = options,
                total = 1
            }
                , serializerSettings)
                , "application/json");
        }

        [HttpPost, ValidateInput(false)]
        public ContentResult EditMainPageOptions(Options options)
        {
            Options mainPage = _domainRepository.Options();
            mainPage.MainPage = options.MainPage;
            mainPage.DisqusDomain = options.DisqusDomain;
            mainPage.AddThisURL = options.AddThisURL;
            mainPage.Author = options.Author;
            mainPage.MetaKeywords = options.MetaKeywords;
            mainPage.MetaDescription = options.MetaDescription;
            return Edit<Options>(mainPage);
        }

        [HttpPost, ValidateInput(false)]
        public ContentResult EditSmtpOptions(Options options)
        {
            Options smtpOptions = _domainRepository.Options();
            smtpOptions.SMPT_Server = options.SMPT_Server;
            smtpOptions.SMPT_Port = options.SMPT_Port;
            smtpOptions.SMPT_UserName = options.SMPT_UserName;
            smtpOptions.SMPT_Password = options.SMPT_Password;
            return Edit<Options>(smtpOptions);
        }

        [HttpPost, ValidateInput(false)]
        public ContentResult EditContacOptions(Options options)
        {
            Options contactOptions = _domainRepository.Options();
            contactOptions.AdminEmail = options.AdminEmail;
            contactOptions.ContactPhone1 = options.ContactPhone1;
            contactOptions.ContactName1 = options.ContactName1;
            contactOptions.ContactPhone2 = options.ContactPhone2;
            contactOptions.ContactName2 = options.ContactName2;
            contactOptions.ContactPhone3 = options.ContactPhone3;
            contactOptions.ContactName3 = options.ContactName3;
            return Edit<Options>(contactOptions);
        }
        #endregion

        #region Reports

        public ActionResult Reports(JqInViewModel jqParams)
        {
            var reports = _domainRepository.Reports(
                  jqParams.page - 1
                , jqParams.rows
                , jqParams.sidx
                , jqParams.sord == "asc"
                , jqParams.name
                , jqParams.hike
                ).ToList();

            var totalReports = _domainRepository.Total<Report>();
            JsonSerializerSettings serializerSettings = new JsonSerializerSettings();
            var converter = new IsoDateTimeConverter();
            converter.DateTimeFormat = "yyyy-MM-dd";
            serializerSettings.Converters.Add(converter);
            return Content(JsonConvert.SerializeObject(new
            {
                page = jqParams.page,
                records = totalReports,
                rows = reports,
                total = Math.Ceiling(Convert.ToDouble(totalReports) / jqParams.rows)
            }
                , serializerSettings)
                , "application/json");
        }

        [HttpPost, ValidateInput(false)]
        public ContentResult AddReport(Report entity)
        {
            return Add<Report>(entity);
        }

        [HttpPost, ValidateInput(false)]
        public ContentResult EditReport(Report entity)
        {
            return Edit<Report>(entity);
        }

        [HttpPost]
        public ContentResult DeleteReport(int id)
        {
            return Delete<Report>(id);
        }

        #endregion

        #region PhotoAlbums

        public ActionResult PhotoAlbums(JqInViewModel jqParams)
        {
            var photoAlbums = _domainRepository.PhotoAlbumSummary(
                  jqParams.page - 1
                , jqParams.rows
                , jqParams.sidx
                , jqParams.sord == "asc"
                , jqParams.name
                , jqParams.hike
                ).ToList();

            var totapPhotoAlbums = _domainRepository.Total<PhotoAlbum>();
            JsonSerializerSettings serializerSettings = new JsonSerializerSettings();
            var converter = new IsoDateTimeConverter();
            converter.DateTimeFormat = "yyyy-MM-dd";
            serializerSettings.Converters.Add(converter);
            return Content(JsonConvert.SerializeObject(new
            {
                page = jqParams.page,
                records = totapPhotoAlbums,
                rows = photoAlbums,
                total = Math.Ceiling(Convert.ToDouble(totapPhotoAlbums) / jqParams.rows)
            }
                , serializerSettings)
                , "application/json");
        }

        [HttpPost, ValidateInput(false)]
        public ContentResult AddPhotoAlbum(PhotoAlbumSummary entity)
        {
            PhotoAlbum album = new PhotoAlbum();
            album.Name = entity.Name;
            album.Description = entity.Description;
            album.Hike = new Hike();
            album.Hike.ID = entity.Hike.ID;
            album.Published  = entity.Published;
            album.Meta = entity.Name;

            ModelState.Clear();

            if (TryValidateModel(album))
            {
                _domainRepository.Add<PhotoAlbum>(album);
                entity.ID = album.ID;
                return Edit<PhotoAlbumSummary>(entity);
            }
            else
            {
                string json = JsonConvert.SerializeObject(new
                {
                    id = 0,
                    success = false,
                    message = "Невозможно внести изменения: " + ModelState.Values.First(x => x.Errors.Count >= 1).Errors[0].ErrorMessage
                });
                return Content(json, "application/json");
            }
        }

        [HttpPost, ValidateInput(false)]
        public ContentResult EditPhotoAlbum(PhotoAlbumSummary entity)
        {
            return Edit<PhotoAlbumSummary>(entity);
        }

        [HttpPost]
        public ContentResult DeletePhotoAlbum(int id)
        {
            return Delete<PhotoAlbum>(id);
        }

        #endregion
    }
}
